#include <Directory.h>
#include <SuperBlock.h>
#include <FCB.h>
#include <iostream>
#include <vector>
#include <DirItem.h>
#include <System.h>
#include <fstream>
#include <sys/stat.h>

//当前目录下是否存在某个名字
bool Directory::has(string name)
{
	Directory* dir = this->getDir(name);
	File* file = this->getFile(name);
	if(dir != 0 || file != 0)
	{
		return true;
	}
	delete dir;
	delete file;
	return false;
}


//获取目录下所有直接子目录
vector<Directory*> Directory::getDirs()
{
	//重新加载fcb
	this->fcb = reloadFile(this->disk, this->fcb);
	//读取目录列表
	vector<Directory*> collection;
	DirItem dirItem;
    string diskname = this->disk;
    for(int i = 0; i < fcb.bytes / 256; i++)  //每256字节代表一个目录表项
    {
        int count = readFile(diskname, fcb, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr != 0) //如是读取正确且地址正确（因为删除后会置0）
        {
        	FCB* fcb = openFile(diskname, this->fcb, dirItem.filename);
        	if(fcb != 0 && fcb->type == 1)    //如果读取正确且是一个目录
        	{
        		Directory* dir = new Directory(*fcb, dirItem.filename);
        		dir->disk = this->disk;       //复制disk
            	collection.push_back(dir);
            	delete fcb;
        	}
        }
    }
	return collection;
}


//获取目录下所有直接文件
vector<File*> Directory::getFiles()
{
	//重新加载fcb
	this->fcb = reloadFile(this->disk, this->fcb);
	//读取文件列表
	vector<File*> collection;
	DirItem dirItem;
    string diskname = this->disk;
    for(int i = 0; i < fcb.bytes / 256; i++)
    {
        int count = readFile(diskname, fcb, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr != 0)
        {
        	FCB* fcb = openFile(diskname, this->fcb, dirItem.filename);
        	if(fcb != 0 && fcb->type == 0)   //如果读取正确，且类型为文件
        	{
        		File* file = new File(*fcb, dirItem.filename);
        		file->disk = this->disk;
            	collection.push_back(file);
            	delete fcb;
        	}
        }
    }
	return collection;
}

//创建文件夹
bool Directory::createDir(string name)
{
	if(createFile(this->disk, this->fcb, name, 1))
	{
		//重新加载fcb
		this->fcb = reloadFile(this->disk, this->fcb);
		return true;
	}
	return false;
}

//删除文件夹
bool Directory::removeDir(string name)
{
	//判断是否是空目录
	int files = 0;  //文件和目录总个数
	DirItem dirItem;
    string diskname = this->disk;
    FCB* dir = openFile(diskname, this->fcb, name);
    if(dir == 0)    //如果不存在
    {
    	return false;
    }
    //数一数要删除的目录的子文件和子目录总个数
    for(int i = 0; i < dir->bytes / 256; i++)
    {
        int count = readFile(diskname, *dir, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr != 0)
        {
        	files++;
        }
    }
    
    delete dir;
    
    if(files != 0)    //如果不是空的目录
    {
    	return false;
    }
    
	if(removeFile(diskname, this->fcb, name))
	{
		return true;
	}
	
	return false;
}

//创建一个空白文件
bool Directory::createAFile(string name)
{
	if(createFile(this->disk, this->fcb, name, 0))
	{
		//重新加载fcb
		this->fcb = reloadFile(this->disk, this->fcb);
		return true;
	}
	return false;
}

//删除一个文件，并释放占用的空间
bool Directory::removeAFile(string name)
{
	string diskname = this->disk;
	if(removeFile(diskname, this->fcb, name))
	{
		return true;
	}
	return false;
}



//打开磁盘并返回根路径
Directory* Directory::getRoot(string diskname)
{
	SuperBlock* superBlock;
    FCB* root;
		
	if(openDisk(diskname, superBlock, root))
	{
		Directory* rootDir = new Directory(*root, "");
		rootDir->disk = diskname;       //初次附值，以后将会传递
		delete superBlock;
		delete root;
		return rootDir;
		
	}else
	{
		return 0;
	}
}


//私有构造函数
Directory::Directory(FCB fcb, string name) : FcbMsg(fcb, name)
{
	
}


//得到一个子文件
//如果文件不存在，则返回0
File* Directory::getFile(string name)                   
{
	DirItem dirItem;
    string diskname = this->disk;
    for(int i = 0; i < fcb.bytes / 256; i++)
    {
        int count = readFile(diskname, fcb, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr != 0)
        {
        	FCB* fcb = openFile(diskname, this->fcb, dirItem.filename);
        	if(fcb != 0 && fcb->type == 0 && dirItem.filename == name)
        	{
        		FCB temp = *fcb;
            	delete fcb;
            	File* file = (new File(temp, dirItem.filename));
            	file->disk = this->disk;
            	return file;
        	}
        }
    }
    return 0;
}

//得到一个子目录
//如果子目录不存在，则返回0
Directory* Directory::getDir(string name)
{
	DirItem dirItem;
    string diskname = this->disk;
    for(int i = 0; i < fcb.bytes / 256; i++)
    {
        int count = readFile(diskname, fcb, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr != 0)
        {
        	FCB* fcb = openFile(diskname, this->fcb, dirItem.filename);
        	if(fcb != 0 && fcb->type == 1 && dirItem.filename == name)
        	{
        		FCB temp = *fcb;
            	delete fcb;
            	Directory* dir = (new Directory(temp, dirItem.filename));
            	dir->disk = this->disk;
            	return dir;
        	}
        }
    }
    
    return 0;
}


//最重要的两个函数之一-导出文件
bool Directory::exportFile(string name, string newName) // name是虚拟磁盘文件名
{
	string diskname = this->disk;
	FCB* fcb = openFile(diskname, this->fcb, name);
    if(fcb == 0)   //如果文件不存在
    {
        return false;
    }
    
    
	ofstream file;
	file.open(newName, ios::binary | ios::out);
	if(file.fail())//如果打开要导出的文件失败
	{
		return false;
	}
	
    cout << "start to download..." << endl;
	char buf[1024];
	int bytes = fcb->bytes;
	int count = 1024;
	int start = 0;
	while(bytes > 0)
	{
		if(count > bytes) count = bytes;
		readFile(diskname, *fcb, buf, start, count);
		file.write(buf, count);
		start += count;
		bytes -= count;
	}
	
	cout << "download succeed" << endl;
	
	file.close();
	return true;
}


//最重要的两个函数之一-导入文件
// name是运行路径下某个文件
bool Directory::importFile(string name, string newName)
{
	if(!createAFile(newName))   //如果创始空文件失败
	{
		cout << "或许没有足够的空间" << endl;
		return false;
	}
	string diskname = this->disk;
	FCB* fcb = openFile(diskname, this->fcb, newName);
	int flag = true;
    if(fcb != 0)               //如果虚拟磁盘内部文件无法打开 
    {
        cout << "start to upload..." << endl;
	    struct stat statbuf;  
	    stat(name.c_str(), &statbuf);  
	    int size=statbuf.st_size;    //获得上传文件的大小
		if ( size != 0 )
		{
	        ifstream ifile;
	        ifile.open(name, ios::binary | ios::in);
	        if(ifile.fail())        //如果文件无法打开
	        {
	            return 0;
	        }
	        
	        cout << "ready to write..." << endl;
	        
	        ifile.seekg(0);
	        int bytes = size;
	        int count = 1024;
	        char buf[1024];
	        int start = 0;
	        while(bytes > 0)
	        {
	            if(count > bytes) count = bytes;
	            ifile.read(buf, count);
	            if(writeFile(diskname, *fcb, buf, start, count) == -1)
	            {
	            	return false;
	            }
	            start += count;
	            bytes -= count;
	            cout << "left:" << bytes << "bytes" << endl;
	        }
	        cout << "write succeed" << endl;
	     }else
	     {
	     	flag = false;	
	     }
	     delete fcb;
    }else
    {
    	flag = false;
    }
    
    return flag;
}

